// Copyright (c) 2023 CHANGLEI. All rights reserved.

library arith;

import 'dart:collection';
import 'dart:core';
import 'dart:math' as math;

import 'package:arith/src/describable.dart';
import 'package:arith/src/parser.dart';

part 'arith_error.dart';

part 'curve.dart';

part 'expression.dart';

part 'math.dart';

part 'operator.dart';

part 'rpn.dart';

part 'variable.dart';

/// 获取value
typedef ValueGetter<T> = T Function();

/// 解析[newExpression]
Expression parse(String expression, [Set<Callable>? callables]) {
  return Parser(expression, callables).parse();
}

/// Created by changlei on 2023/6/7.
///
/// 元素
sealed class Arith implements Describable {}

/// 终点元素
sealed class Factor implements Arith {}

/// 符号，包括[Operator]，[Math]，[Curve]
sealed class Symbols implements Factor {
  /// 符号，包括[Operator]，[Math]，[Curve]
  const Symbols();

  /// 解析
  static Symbols? maybeOf(String s) {
    return switch (s) {
      final s when Operator2.maybeOf(s) != null => Operator2.of(s),
      final s when Curve.maybeOf(s) != null => Curve.of(s),
      final s when Math.maybeOf(s) != null => Math.of(s),
      _ => null,
    };
  }
}

/// 可操作元素，包括[Operator]，[Math]，[Variables]
sealed class Operable implements Factor {}

/// 算数运算符，包括[Operator1]，[Operator2]
sealed class Operator implements Symbols, Operable {
  /// 优先级
  int get priority;
}

/// 函数参数，包括[Variable1]，[Expression]
sealed class Argument implements Describable {
  @override
  String toDescribe([bool isTight = false, Map<String, ValueGetter<num>>? variables]);
}

/// 扩展公式的拼接
extension JointedArith on Arith {
  /// 拼接
  Expression operator +(Arith arith) {
    final current = this;
    final elements = switch (current) {
      Factor() => [current],
      Expression() => [...current],
    };
    elements.addAll(
      switch (arith) {
        Factor() => [arith],
        Expression() => arith,
      },
    );
    return Expression(elements);
  }
}

/// 优先级
extension PriorityFactor on Factor {
  /// 优先级
  int get priority {
    return switch (this) {
      Operator(:final priority) => priority,
      Math(:final priority) => priority,
      _ => 0,
    };
  }

  /// 优先级的`>`
  bool operator >(Factor other) => priority > other.priority;

  /// 优先级的`>=`
  bool operator >=(Factor other) => priority >= other.priority;

  /// 优先级的`<`
  bool operator <(Factor other) => priority < other.priority;

  /// 优先级的`<=`
  bool operator <=(Factor other) => priority <= other.priority;
}
